使用useState數據進行更新時,不能即時獲得最新數據。
const [name, setName] = useState('dp')
const handleTest = () => {
console.log(name) //dp
setName('dx1')
console.log(name) //dp
}
解決方法:
一、使用useEffect
useEffect(() => {
console.log(name) //dx1
},[name])
二、建立新的變數保存新數據
const [name, setName] = useState('dp');
const handleTest = () => {
console.log(name) //dp
const newName = "dx1"
setName(newName)
console.log(newName) //dx1
}
* 僅能在最上層調用Hook,不能在循環(map)、巢狀component...等中調用useState()。
* 多個useState()調用時,渲染調用順序必須相同。
* 僅能從React函數組件(component)或自定義Hook中調用useState()。
const [a, setA] = useState({c:1})
// oldA之前的a,return設定的新值
setA((oldA) => {
return {c: oldA.c + 1}
})
const contentObj = {name:'dp'}
const [content, setContent] = useState(contentoObj)
setContent((oldContent) => {
oldContent.age = 18
return {oldContent} // 返回新的數據,useEffect才能檢測到變化
})
以下Code會在頁面渲染兩次
const [isLoading, setIsLoading] = useState(false)
const [data, setData] = useState([])
useEffect(async() => {
const res = await axios.get("XXX")
setIsLoading(false)
setData(res)
},[])
在React中,同步Code會進行合併渲染,異步則不會合併,而以下Code則只會渲染一次
const [isLoading, setIsLoading] = useState(false)
const [data, setData] = useState([])
useEffect(() => {
setIsLoading(false)
setData({a:1})
},[])
但如果依然需要使用到異步那就需要使用以下幾種方式
方法一、多個狀態合併至一個狀態
const [request, setRequest] = useState({ isLoading: true, data: null });
useEffect(async () => {
const res = await axios.get("xxx");
setRequest({ isLoading: false, data: res });
}, []);
但如果單純只想setState一個值時,會需要將其他值也傳進去,否則將會遺失。React內部並不會自動幫你做合併
setRequest({ data: res }); // isLoading 值遺失了。
//解決方法使用展開運算符(Spread Operator)
setRequest({ ...request, data: res });
// 或者
setRequest((prevState) => ({ ...prevState, data: res }));
方法二、自定義一個合併值的Hook
const useMergeState = (initialState) => {
const [state, setState] = useState(initialState);
const setMergeState = (newState) =>
setState((prevState) => ({ ...prevState, newState }));
return [state, setMergeState];
};
/* 使用 */
const [request, setRequest] = useMegeState({ isLoading: false, data: null });
useEffect(async () => {
const res = await axios.get("xxx");
setRequest({ isLoading: true, data: res });
// ...
setRequest({ data: { a: 1 } }); // isLoading 狀態不會遺失,而且值仍是 true
}, []);
方法三、使用useReducer來管理各值,而非useState
const [request, setRequest] = useReducer(
(prevState, newState) => {
const newWithPrevState = typeof newState === "function" ? newState(prevState) : newState;
return{ ...prevState, newWithPrevState })
},
{ isLoading: false, data: null }
);
useEffect(async () => {
const res = await axios.get("xxx");
setRequest((prevState) => {
console.log(prevState)
return { isLoading: true, data: res }
});
// ...
setRequest({ data: { a: 1 } }); // isLoading 狀態不會遺失,而且值仍是 true
}, []);